package com.sys.basics.config.socketio.nameSpaceListener;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.corundumstudio.socketio.*;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.corundumstudio.socketio.protocol.Packet;
import com.corundumstudio.socketio.store.pubsub.DispatchMessage;
import com.sys.basics.config.socketio.data.ConsumerAndClientData;
import com.sys.basics.config.socketio.data.DispatchData;
import com.sys.basics.config.socketio.data.ReceivedData;
import com.sys.basics.entity.SysUser;
import com.sys.basics.service.SysUserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Slf4j
@Component
public class WebEventListener extends AbstractEventLintener implements InterfaceEventListener {

    @Autowired
    SysUserService sysUserService;

    private ConcurrentMap<UUID, ConsumerAndClientData<SysUser>> webClientMap = new ConcurrentHashMap<>();

    @Override
    @OnConnect
    public void onConnect(SocketIOClient client) {
        String defaultRoom = client.getNamespace().getName();
        UUID sessionId = client.getSessionId();

        HandshakeData data = client.getHandshakeData();
        String account = data.getSingleUrlParam("account");

        if (StringUtils.isEmpty(account)) {
            client.sendEvent("message", "请配置连接账号");
            client.disconnect();
            return;
        }
        SysUser user = sysUserService.getByAccount(account);
        if (ObjectUtil.isNull(user)) {
            client.sendEvent("message", "账号不存在");
            client.disconnect();
            return;
        }
        log.info(">>>[WEB]->[{}]->[{}][{}] 连接成功<<<", defaultRoom, account, sessionId);
        ConsumerAndClientData consumerAndClientData = new ConsumerAndClientData(user, client);
        webClientMap.put(sessionId, consumerAndClientData);
        //测试语句
        client.sendEvent("clientConnect", "客户端连接成功");
    }

    @Override
    @OnDisconnect
    public void onDisconnect(SocketIOClient client) {
        String defaultRoom = client.getNamespace().getName();
        UUID sessionId = client.getSessionId();

        HandshakeData data = client.getHandshakeData();
        String account = data.getSingleUrlParam("account");

        log.info(">>>[WEB]->[{}]->[{}][{}] 断开连接<<<", defaultRoom, account, sessionId);
        webClientMap.remove(sessionId);
    }

    @Override
    @OnEvent("message")
    public void onMessage(SocketIOClient client, ReceivedData receivedData, AckRequest ackSender) {
        String defaultRoom = client.getNamespace().getName();
        UUID sessionId = client.getSessionId();

        HandshakeData data = client.getHandshakeData();
        String account = data.getSingleUrlParam("account");

        ackSender.sendAckData("服务器已收到 " + account + " 发送的消息");

        log.info(">>>[WEB]->[{}]->收到客户[{}][{}]->发送的消息 <<< \n {}", defaultRoom, account, sessionId, JSONObject.toJSONString(receivedData));
        //测试语句
        client.sendEvent("serverReceivedMsg", JSONObject.toJSON(receivedData));
    }

    /**
     * @author: ares
     * @date: 2021/11/8 13:20
     * @description: 推送数据到某个客户端
     */
    @Override
    public void sendEventToClient(DispatchMessage msg) {
        String nsp = msg.getNamespace();
        String roomName = msg.getRoom();
        Packet packet = msg.getPacket();
        String eventName = packet.getName();
        DispatchData dispatchData = packet.getData();
        Long consumerId = dispatchData.getConsumerId();
        Object messageData = dispatchData.getData();

        ArrayList<SocketIOClient> socketIOClients = new ArrayList<>();

        webClientMap.forEach((uuid, consumerAndClientData) -> {
            SysUser consumer = consumerAndClientData.getConsumer();
            if (consumerId.equals(consumer.getId())) {
                socketIOClients.add(consumerAndClientData.getClient());
            }
        });

        if (socketIOClients.size() == 0) return;
        socketIOClients.forEach(client -> {
            client.sendEvent(eventName, new VoidAckCallback() {
                @Override
                protected void onSuccess() {
                    log.info(">>>[{}]->[{}]->客户[{}][{}] 已收到服务器推送的消息<<<", nsp, roomName, consumerId, client.getSessionId());
                    //测试语句
                    client.sendEvent("clientReceivedMsg", "客户端已收到服务器推送的数据");
                }
            }, messageData);
        });

    }

    /**
     * @author: ares
     * @date: 2021/11/8 14:28
     * @description: 广播消息
     */
    @Override
    public void sendEventToClients(DispatchMessage msg) {
        String nsp = msg.getNamespace();
        String roomName = msg.getRoom();
        Packet packet = msg.getPacket();
        String eventName = packet.getName();
        DispatchData dispatchData = packet.getData();
        Object messageData = dispatchData.getData();
        SocketIONamespace socketIONamespace = nettySocketIOServer.getNamespace(nsp);
        BroadcastOperations clients = socketIONamespace.getRoomOperations(roomName);
        clients.sendEvent(eventName, messageData, new BroadcastAckCallback(Object.class) {
            @Override
            protected void onAllSuccess() {
                log.info(">>>[{}]->[{}]->广播消息[{}],所有客户都已收到服务器推送的消息<<<", nsp, roomName, eventName);
            }
        });
    }

    ;
}
